
#include "HttpUtil.h"
#include "mongoose.h"
#include <cstdlib>
#include <cstring>

bool HttpUtil::startsWith(const mg_str& src, const char* substr)
{
	return startsWith(src, substr, strlen(substr));
}

bool HttpUtil::startsWith(const mg_str& src, const char* substr, size_t len)
{
	if (src.len < len)
	{
		return false;
	}

	int ret = memcmp(src.p, substr, len);
	return ret == 0;
}

bool HttpUtil::endsWith(const mg_str& src, const char* substr)
{
    return endsWith(src, substr, strlen(substr));
}

bool HttpUtil::endsWith(const mg_str& src, const char* substr, size_t len)
{
    if (src.len < len)
    {
        return false;
    }

    int ret = memcmp(src.p + (src.len - len), substr, len);
    return ret == 0;
}

bool HttpUtil::getVar(const struct mg_str *buf, const char *name, std::string& value)
{
	bool found = false;
	char text[1024] = {0};
	int ret = mg_get_http_var(buf, name, text, sizeof(text));
	if (ret > 0)
	{
		value = text;
		found = true;
	}
	return found;
}

bool HttpUtil::getVar(const struct mg_str *buf, const char *name, int& value)
{
	bool found = false;
	char text[1024] = {0};
	int ret = mg_get_http_var(buf, name, text, sizeof(text));
	if (ret > 0)
	{
		value = strtol(text, NULL, 10);
		found = true;
	}
	return found;
}


bool HttpUtil::getVar(const struct mg_str *buf, const char *name, double& value)
{
	bool found = false;
	char text[1024] = {0};
	int ret = mg_get_http_var(buf, name, text, sizeof(text));
	if (ret > 0)
	{
		value = strtod(text, NULL);
		found = true;
	}
	return found;
}

bool HttpUtil::getVar(const struct mg_str *buf, const char *name, int64_t& value)
{
	bool found = false;
	char text[1024] = {0};
	int ret = mg_get_http_var(buf, name, text, sizeof(text));
	if (ret > 0)
	{
#if defined(_MSC_VER) && (_MSC_VER < 1900 )
		value = _strtoi64(text, NULL, 10);
#else
		value = strtoll(text, NULL, 10);
#endif //
		found = true;
	}
	return found;
}

bool HttpUtil::getVar(const struct mg_str *buf, const char *name, bool& value)
{
	bool found = false;
	char text[1024] = {0};
	int ret = mg_get_http_var(buf, name, text, sizeof(text));
	if (ret > 0)
	{
		if (mg_ncasecmp(text, "false", strlen("false")) == 0)
		{
			value = false;
		}
		else
		{
			if (isDigit(text, ret))
			{
				int num = strtol(text, NULL, 10);
				value = (num > 0);
			}
			else
			{
				value = false;
			}
		}

		found = true;
	}
	return found;
}

bool HttpUtil::isDigit(const char* str, size_t len)
{
	if ((str == NULL) || (len == 0))
	{
		return false;
	}

	bool result = true;
	for (size_t i = 0; i < len; i ++)
	{
		if (str[0] == '0')
		{
			break;
		}

		if (!::isdigit(str[i]))
		{
			result = false;
			break;
		}
	}
	return result;
}

std::string HttpUtil::optVar(const struct mg_str *buf, const char *name, const char* defValue)
{
	std::string value(defValue);
	getVar(buf, name, value);
	return value;
}

std::string HttpUtil::optVar(const struct mg_str *buf, const char *name, const std::string& defValue)
{
	std::string value(defValue);
	getVar(buf, name, value);
	return value;
}

double HttpUtil::optVar(const struct mg_str *buf, const char *name, double defValue)
{
	double value(defValue);
	getVar(buf, name, value);
	return value;
}

int HttpUtil::optVar(const struct mg_str *buf, const char *name, int defValue)
{
	int value(defValue);
	getVar(buf, name, value);
	return value;
}

bool HttpUtil::optVar(const struct mg_str *buf, const char *name, bool defValue)
{
	bool value(defValue);
	getVar(buf, name, value);
	return value;
}

int64_t HttpUtil::optVar(const struct mg_str *buf, const char *name, int64_t defValue)
{
	int64_t value(defValue);
	getVar(buf, name, value);
	return value;
}

bool HttpUtil::isPost(const mg_str& method)
{
	return mg_vcasecmp(&method, "POST") == 0;
}

bool HttpUtil::isGet(const mg_str& method)
{
	return mg_vcasecmp(&method, "GET") == 0;
}

bool HttpUtil::isOption(const mg_str& method)
{
	return mg_vcasecmp(&method, "OPTIONS") == 0;
}

bool HttpUtil::getRemoteAddr(mg_connection* connection, std::string& ip)
{
	char buf[128] = { 0 };
	mg_conn_addr_to_str(connection, buf, sizeof(buf), MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_REMOTE);
	ip = buf;
	return true;
}

bool HttpUtil::getRemoteName(mg_connection* connection, std::string& ip)
{
	char buf[128] = { 0 };
	mg_conn_addr_to_str(connection, buf, sizeof(buf), MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT | MG_SOCK_STRINGIFY_REMOTE);
	ip = buf;
	return true;
}

bool HttpUtil::decodeChunked(const char* p, size_t len, std::string& data)
{
	mg_str src = mg_mk_str_n(p, len);
	mg_str eol = mg_mk_str("\r\n");
	const char* end = p + len;

	int count = 0;

 	while (true)
	{
		const char* content = mg_strstr(src, eol);
		if (content == nullptr)
		{
			break;
		}

		std::string prefix(p, content - p);
		int size = (int)strtol(prefix.c_str(), NULL, 16);
		if (size <= 0)
		{
			break;
		}

		data.append(content + 2, size);

		const char* begin = content + 2 + size;
		src = mg_mk_str_n(begin, end - begin);

	}

	return count > 0;
}

bool HttpUtil::getHeader(const http_message* msg, const char* name, std::string& value)
{
	bool got = false;
	for (int i = 0; i < MG_MAX_HTTP_HEADERS; ++i)
	{
		const mg_str& header = msg->header_names[i];
		if (header.len <= 0)
		{
			break;
		}

		if (mg_vcasecmp(&header, name) == 0)
		{
			value.assign(msg->header_values[i].p, msg->header_values[i].len);
			got = true;
			break;
		}
	}
	return got;
}